package link.jfire.socket.socketserver.transfer.handler.socket;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.CompletionHandler;
import java.nio.channels.InterruptedByTimeoutException;
import javax.annotation.Resource;
import link.jfire.baseutil.collection.ByteBufferPool;
import link.jfire.baseutil.collection.ByteCache;
import link.jfire.baseutil.simplelog.ConsoleLogFactory;
import link.jfire.baseutil.simplelog.Logger;
import link.jfire.socket.socketserver.bus.ActionType;
import link.jfire.socket.socketserver.bus.ServerChannelInfo;
import link.jfire.socket.socketserver.exception.LessThanProtocolException;
import link.jfire.socket.socketserver.exception.NotFitProtocolException;
import link.jfire.socket.socketserver.exception.NotIntactDataException;
import link.jfire.socket.socketserver.storage.Entry;
import link.jfire.socket.socketserver.storage.WritePacket;
import link.jfire.socket.socketserver.storage.ringarray.RingArray;
import link.jfire.socket.socketserver.util.CheckReadBuffer;
import link.jfire.socket.socketserver.util.HeadFactory;

@Resource
public class ChannelReadHandler implements CompletionHandler<Integer, ServerChannelInfo>
{
    private Logger      logger = ConsoleLogFactory.getLogger();
    @Resource
    private HeadFactory headFactory;
    private RingArray   ringArray;
    
    @Override
    public void completed(Integer read, ServerChannelInfo channelInfo)
    {
        if (read == -1)
        {
            channelInfo.close();
            return;
        }
        ByteBuffer readBuffer = channelInfo.getReadBuffer();
        logger.trace("读取字节{}，buffer状态{}", read, readBuffer.toString());
        readBuffer.flip();
        while (true)
        {
            try
            {
                buildMessageAndSend(readBuffer, channelInfo);
            }
            catch (NotFitProtocolException e)
            {
                logger.debug("协议错误，关闭链接");
                channelInfo.close();
                return;
            }
            catch (LessThanProtocolException e)
            {
                readBuffer.compact();
                logger.trace("压缩完毕，继续读取。buffer状态{}", readBuffer.toString());
                channelInfo.startReadWait();
                return;
            }
            catch (NotIntactDataException e)
            {
                readBuffer.compact();
                readBuffer = ByteBufferPool.expandToSize(e.getNeedSize(), readBuffer);
                logger.debug("扩展容量，继续读取,需要的大小是{},buffer状态{}", e.getNeedSize(), readBuffer.toString());
                channelInfo.setReadBuffer(readBuffer);
                channelInfo.continueRead();
                return;
            }
        }
    }
    
    private void buildMessageAndSend(ByteBuffer buffer, ServerChannelInfo channelInfo) throws NotFitProtocolException, LessThanProtocolException, NotIntactDataException
    {
        int length = CheckReadBuffer.checkReadBuffer(buffer, headFactory);
        buffer.position(buffer.position() + 5);
        byte command = buffer.get();
        // 跳过客户端发来的报文中的结果位
        buffer.get();
        buffer.position(buffer.position() + 4);
        long next = ringArray.next();
        Entry entry = ringArray.entryAt(next);
        WritePacket packet = new WritePacket(channelInfo, next);
        entry.setNewData(ActionType.CLIENT_SEND, command, packet, channelInfo);
        ByteCache businessData = entry.getBusinessData().clear();
        businessData.putByteBuffer(buffer, length);
        buffer.position(buffer.position() + length);
        channelInfo.addWritePacket(packet);
        logger.debug("发布序号:{}", next);
       
        ringArray.publish(next);
       
    }
    
    @Override
    public void failed(Throwable exc, ServerChannelInfo channelInfo)
    {
        if (logger.isDebugEnabled())
        {
            logger.debug("通道{}剩余包数{}", channelInfo.getAddress(), channelInfo.left());
        }
        if (exc instanceof ClosedChannelException || channelInfo.getReadBuffer().position() == 0)
        {
            logger.debug("通道{}关闭", channelInfo.getAddress());
        }
        else if (exc instanceof InterruptedByTimeoutException)
        {
            if (logger.isDebugEnabled())
            {
                logger.debug("通道{}读取超时时间到达，关闭", channelInfo.getAddress());
            }
        }
        else if (exc instanceof IOException && exc.getMessage().contains("指定的网络名不再可用"))
        {
            logger.debug("远端socket异常关闭");
        }
        else
        {
            logger.error("读取异常,当前读取" + channelInfo.getReadBuffer().position(), exc);
        }
        channelInfo.close();
    }
    
    public void setRingArray(RingArray ringArray)
    {
        this.ringArray = ringArray;
    }
}
